import logging
import json
import paho.mqtt.client as paho
from paho.mqtt.client import MQTTMessage
_log = logging.getLogger('mqtt')


class MqttClient:
    def __init__(self, config: dict):
        self._config = config
        self.client = paho.Client(protocol=paho.MQTTv311)
        self.client.on_connect = lambda _, __, ____, rc: self.on_connect(rc)
        self.client.on_subscribe = lambda _, __, ____, rc: self.on_subscribe(
            rc)
        self.client.on_message = self.on_message
        self.client.on_disconnect = lambda _, __, ___: self._on_disconnect()
        self.listeners = []
        self.rpcTopicList = []

    def register_listener(self, callback):
        """允许其他类注册监听函数"""
        self.listeners.append(callback)

    # 添加topic列表
    def addTopicList(self, callback):
        self.rpcTopicList.extend(callback)

    # 连接回调参数 rc: 0 成功，1协议版本不正确，2客户端标识符无效，3服务不可用，4用户名或密码错误，5未授权，6不可用
    def on_connect(self, rc: int):
        if rc == 0:
            _log.info("mqtt连接成功")
            rpclist = list(set(self.rpcTopicList))
            for item in rpclist:
                _log.info(f"订阅主题:{item}")
                self.client.subscribe(topic=item)
        else:
            _log.error(f"mqtt连接失败：错误码{rc}")

    def on_subscribe(self, rc: int):
        _log.info("mqtt订阅成功")

    # 断开连接
    def _on_disconnect(self):
        _log.error(f"mqtt断开连接了")

    # 收到消息
    def on_message(self, client, userdata, msg: MQTTMessage):
        topic: str = msg.topic
        msg_obj = msg.payload.decode('utf-8')
        try:
            payload = json.loads(msg_obj)
            _log.info(f"收到指令{topic}消息:{payload}")
            topicName = topic.split("/")[-1]
            for cb in self.listeners:
                try:
                    cb(topicName, payload)
                except Exception as e:
                    _log.error(f"分发消息到 {cb} 失败: {e}")
        except json.JSONDecodeError:
            _log.error(f"json解析失败:{topic}:{msg_obj}")

    # 发送消息
    def send_msg(self, topic: str, msg: dict, qos: int = 0):
        # _log.info(f"mqtt发送数据:{topic}:{msg}")
        self.client.publish(topic, json.dumps(msg), qos)

    def start(self):
        try:
            if "user" in self._config:
                self.client.username_pw_set(
                    self._config["user"], self._config["password"])
            self.client.connect_async(
                self._config["host"], self._config["port"])
            self.client.loop_start()
        except Exception as e:
            _log.error("mqtt启动失败", e)

    def stop(self):
        self.client.loop_stop()
